package sudoku

import (
	"fmt"
)

// GridType reprents grid of 9 x 9 sudoku game
// It's a diverse matrix
// row-column from 0 to 8
// {1:{2:3, 3:4}, 2:{5:1, 4:1}}/ GridType reprents sudoku grid
type GridType [][]int

// MakeGridType makes gridType
func MakeGridType() GridType {
	g := make(GridType, 9)
	for i := range g {
		g[i] = make([]int, 9)
	}
	return g
}

// Size returns the element in grid
func (g GridType) Size() int {
	size := 0
	for _, row := range g {
		for _, val := range row {
			if val != 0 {
				size++
			}
		}
	}
	return size
}

// Set value to grid
func (g GridType) Set(i, j, val int) {
	g[i][j] = val
}

// MakeGridFromString makes grid from string
func MakeGridFromString(s string) (GridType, error) {
	g := MakeGridType()
	err := g.Unmarshal(s)
	return g, err
}

// Marshal marshals grid, the format is '1...2..'(81 bytes)
func (g *GridType) Marshal() (string, error) {
	bytes := make([]byte, 81)
	curIdx := 0
	for _, row := range *g {
		for _, value := range row {
			if value == 0 {
				bytes[curIdx] = '.'
			} else {
				bytes[curIdx] = byte(value + '0')
			}
			curIdx++
		}
	}
	return string(bytes), nil
}

// Unmarshal unmarshals from string
func (g *GridType) Unmarshal(data string) error {
	if len(data) != 81 {
		return fmt.Errorf("length of data is invalid: %d", len(data))
	}

	for idx, ch := range []byte(data) {
		row := idx / 9
		col := idx % 9
		if ch == '.' {
			(*g)[row][col] = 0
		} else if ch >= '1' && ch <= '9' {
			(*g)[row][col] = int(ch - '0')
		} else {
			return fmt.Errorf("invalid char: %c at %d", ch, idx)
		}
	}
	return nil
}
